package com.sunlake.spring.main.common.utils;

import com.sunlake.spring.main.config.JwtConfig;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.crypto.Cipher;
import javax.crypto.spec.OAEPParameterSpec;
import javax.crypto.spec.PSource;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.NoSuchAlgorithmException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.spec.MGF1ParameterSpec;
import java.util.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 提供 RSA-OAEP(SHA-256) 加解密能力，用于登录口令的前端加密后后端解密。
 * 如果未配置 RSA 私钥，则回退为明文模式（直接返回原始输入）。
 */
@Component
public class RsaCryptoService {
    private static final Logger log = LoggerFactory.getLogger(RsaCryptoService.class);
    @Autowired
    private JwtConfig jwtConfig;

    private PrivateKey privateKey;
    private PublicKey publicKey; // 目前未用，保留扩展

    @PostConstruct
    public void init() {
        try {
            String privatePem = null;
            String publicPem = null;

            // 1. 直接路径优先（privateKeyPath/publicKeyPath 支持 classpath:, file:, 普通路径）
            if (jwtConfig.getPrivateKeyPath() != null && !jwtConfig.getPrivateKeyPath().isBlank()) {
                try {
                    privatePem = RsaKeyUtil.readLocation(jwtConfig.getPrivateKeyPath().trim());
                    log.info("[RSA] Loaded private key from path: {} (length={})", jwtConfig.getPrivateKeyPath(), privatePem.length());
                } catch (IOException ex) {
                    log.error("[RSA] Failed to read privateKeyPath: {} => {}", jwtConfig.getPrivateKeyPath(), ex.getMessage());
                }
            } else if (jwtConfig.getPrivateKeyPem() != null && !jwtConfig.getPrivateKeyPem().isBlank()) {
                privatePem = jwtConfig.getPrivateKeyPem().trim();
                log.info("[RSA] Loaded private key from inline PEM (length={})", privatePem.length());
            } else {
                log.info("[RSA] No private key configured (privateKeyPath/privateKeyPem both blank)");
            }

            if (jwtConfig.getPublicKeyPath() != null && !jwtConfig.getPublicKeyPath().isBlank()) {
                try {
                    publicPem = RsaKeyUtil.readLocation(jwtConfig.getPublicKeyPath().trim());
                    log.info("[RSA] Loaded public key from path: {} (length={})", jwtConfig.getPublicKeyPath(), publicPem.length());
                } catch (IOException ex) {
                    log.error("[RSA] Failed to read publicKeyPath: {} => {}", jwtConfig.getPublicKeyPath(), ex.getMessage());
                }
            } else if (jwtConfig.getPublicKeyPem() != null && !jwtConfig.getPublicKeyPem().isBlank()) {
                publicPem = jwtConfig.getPublicKeyPem().trim();
                log.info("[RSA] Loaded public key from inline PEM (length={})", publicPem.length());
            } else {
                log.info("[RSA] No public key configured (publicKeyPath/publicKeyPem both blank)");
            }

            // ====== 解析阶段 ======
            // 只要有私钥就尝试解析私钥；公钥可选（用于验证 JWT 签名或前端加密）
            if (privatePem != null) {
                String firstLine = privatePem.lines().findFirst().orElse("(empty)");
                log.debug("[RSA] Private PEM first line: {}", firstLine);
                // 如果误把公钥粘贴到了 privateKeyPem，直接警告并跳过解析
                if (firstLine.contains("BEGIN PUBLIC KEY")) {
                    log.error("[RSA] privateKeyPem contains a PUBLIC KEY header; provide a PRIVATE KEY or RSA PRIVATE KEY block.");
                } else {
                    try {
                        privateKey = RsaKeyUtil.parsePrivateKeyPem(privatePem);
                        log.info("[RSA] Private key parsed successfully");
                    } catch (Exception ex) {
                        log.error("[RSA] Private key parse failed: {}", ex.getMessage());
                    }
                }
            }
            if (publicPem != null) {
                String firstLinePub = publicPem.lines().findFirst().orElse("(empty)");
                log.debug("[RSA] Public PEM first line: {}", firstLinePub);
                try {
                    publicKey = RsaKeyUtil.parsePublicKeyPem(publicPem);
                    log.info("[RSA] Public key parsed successfully");
                } catch (Exception ex) {
                    log.error("[RSA] Public key parse failed: {}", ex.getMessage());
                }
            }

            if (privateKey == null) {
                log.warn("[RSA] Private key still null after init; will fallback to plaintext password handling.");
            }
        } catch (Exception e) {
            log.error("[RSA] Unexpected error during key init: {}", e.getMessage());
            privateKey = null;
            publicKey = null;
        }
    }

    /**
     * 解密前端 base64 的 RSA-OAEP 密文。如果未启用RSA则直接返回原始参数。
     * @param base64Cipher 前端提交的密文（Base64）或明文
     * @return 明文密码；解密失败返回 null
     */
    public String decryptBase64(String base64Cipher) {
        if (base64Cipher == null || base64Cipher.isBlank()) {
            return null;
        }
        if (privateKey == null) {
            return base64Cipher; // 未启用RSA直接返回
        }
        try {
            String norm = base64Cipher.trim().replace(" ", "+").replace("\r", "").replace("\n", "");
            byte[] cipherBytes;
            try {
                // 先尝试标准Base64
                cipherBytes = java.util.Base64.getDecoder().decode(norm);
            } catch (IllegalArgumentException e1) {
                // 尝试URL安全Base64
                cipherBytes = java.util.Base64.getUrlDecoder().decode(norm);
            }
            Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
            OAEPParameterSpec oaep = new OAEPParameterSpec(
                    "SHA-256",
                    "MGF1",
                    new MGF1ParameterSpec("SHA-256"),
                    PSource.PSpecified.DEFAULT
            );
            cipher.init(Cipher.DECRYPT_MODE, privateKey, oaep);
            byte[] plainBytes = cipher.doFinal(cipherBytes);
            return new String(plainBytes);
        } catch (Exception e) {
            log.warn("RSA解密失败，回退明文处理: {}", e.getMessage());
            return base64Cipher;
        }
    }
}
